package com.ruoyi.common.utils;

import java.lang.reflect.Field;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

import com.alibaba.fastjson2.JSONObject;

/**
 * 常用工具类
 * 
 * @author 甘露华
 */
public class MyUtils
{

    // md5加密
    public static String md5(String plainText) {
        byte[] secretBytes = null;
        try {
            // getBytes() 是Java编程语言中将一个字符串转化为一个字节数组byte[]的方法
            secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("没有md5这个算法！");
        }
        String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
        // 如果生成数字未满32位，需要前面补0
        for (int i = 0; i < 32 - md5code.length(); i++) {
            md5code = "0" + md5code;
        }
        return md5code;
    }

    // 日期转string
    public static Date getTody() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    // 日期转string
    public static String formatDate(Date date, String type) {
        String t = "yyyy-MM-dd";
        if (type == "yyyy-MM-dd HH:mm:ss") {
            t = "yyyy-MM-dd HH:mm:ss";
        } else {
            t = "yyyy-MM-dd";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(t);
        return sdf.format(date);
    }

    // String转换为java.util.Date
    public static Date formatStringToDate(String str, String type) {
        String t = "yyyy-MM-dd HH:mm:ss";
        if (type == "yyyy-MM-dd HH:mm:ss") {
            t = "yyyy-MM-dd HH:mm:ss";
        } else if (type == "HH:mm:ss") {
            t = "HH:mm:ss";
        } else {
            t = "yyyy-MM-dd";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(t);
        Date date = null; // 初始化date
        try {
            date = sdf.parse(str); // Mon Jan 14 00:00:00 CST 2013
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    // 生成随机码
    public static String createRandomCode() {
        return new Date().getTime() + UUID.randomUUID().toString().replace("-", "");
    }

    // 生成订单号
    public static String getOrderIdByUUId() {
        int machineId = 1;// 最大支持1-9个集群机器部署
        int hashCodeV = UUID.randomUUID().toString().hashCode();
        if (hashCodeV < 0) {// 有可能是负数
            hashCodeV = -hashCodeV;
        }
        // 0 代表前面补充0
        // 4 代表长度为4
        // d 代表参数为正数型
        return machineId + String.format("%015d", hashCodeV);
    }

    // 时间+随机数+userId 生成订单号
    public static String getOrderNoByTimeAndId(Long userId) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String newDate = sdf.format(new Date());
        String result = "";
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            result += random.nextInt(10);
        }
        String resultStr = newDate + userId.toString() + result;
        return resultStr;
    }

    /**
     * 日期增加一天
     *
     * @param day 日期str
     * @return 加上几天后的日期
     */
    public static String addDay(String day, int i) {
        long iadd = 24L * 3600L * 1000L * i;
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            long r = f.parse(day).getTime() + iadd;
            Date d = new Date(r);
            return f.format(d);
        } catch (Exception ex) {
            return day;
        }
    }

    public static List<Integer> StringSetToIntegerList(Set<String> set) {
        List<Integer> list = new ArrayList<>();
        for (String s : set) {
            list.add(Integer.parseInt(s));
        }
        return list;
    }

    // 利用正则表达式判断字符串是否是数字
    public static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    // 日期计算
    public static Date getCountDate(int num) {
        Date date = new Date();
        return new Date(date.getTime() + ((long) num * 24 * 60 * 60 * 1000));
    }

    /**
     * 指定日期 加上/减少 天数后的日期
     *
     * @param n       为增加的天数
     * @param newDate 创建时间
     * @return
     * @throws ParseException
     */
    public static String getBeforeDay(String newDate, Integer n) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date currdate = format.parse(newDate);
            Calendar calendar = Calendar.getInstance(); // 得到当前时间
            calendar.setTime(currdate); // 设置为传进来的那天
            calendar.add(Calendar.DATE, -n); // 得到前N天
            currdate = calendar.getTime();
            String result = format.format(currdate);
            return result;
        }catch (Exception e) {
            System.out.println("getBeforeDay() === 指定日期 加上/减少 天数后的日期异常:" + e.getMessage());
            return null;
        }
    }

    // 获取最近N天 最近今天的日期
    public static Date getDateAdd(int day) {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, -day + 1);
        return c.getTime();
    }

    // 获取最近N天 最近今天的日期
    public static List<String> getDaysBetwwen(int day) { // 最近几天日期
        List<String> dayList = new ArrayList<>();
        Calendar start = Calendar.getInstance();
        start.setTime(getDateAdd(day));
        Long startTIme = start.getTimeInMillis();
        Calendar end = Calendar.getInstance();
        end.setTime(new Date());
        Long endTime = end.getTimeInMillis();
        Long oneDay = 1000 * 60 * 60 * 24l;
        Long time = startTIme;
        while (time <= endTime) {
            Date d = new Date(time);
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            dayList.add(df.format(d));
            time += oneDay;
        }
        return dayList;
    }

    /**
     * 判断时间是否在时间段内
     *
     * @param nowTime
     * @param beginTime
     * @param endTime
     * @return
     */
    public static boolean belongCalendar(Date nowTime, Date beginTime,
                                         Date endTime) {
        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(beginTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        if (date.after(begin) && date.before(end)) {
            return true;
        } else {
            return false;
        }
    }

    // 随机生成邀请码
    public static String createShareCode(Integer num) {
        int maxNum = 36;
        int i;
        int count = 0;
        char[] str = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
                'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
                'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
        StringBuffer code = new StringBuffer("");
        Random r = new Random();
        while (count < num) {
            i = Math.abs(r.nextInt(maxNum));
            if (i >= 0 && i < str.length) {
                code.append(str[i]);
                count++;
            }
        }
        return code.toString();
    }

    // 实体对象转成Map
    public static Map<String, Object> object2Map(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }
        Class<? extends Object> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    // 生成6位数字验证码
    public static String getSixVerifyCode() {
        int max = 999999, min = 1;
        int ran2 = (int) (Math.random() * (max - min) + min);
        return new DecimalFormat("000000").format(ran2);
    }

    /**
     * 校验银行卡卡号
     */
    public static boolean checkBankCard(String cardId) {
        char bit = getBankCardCheckCode(cardId
                .substring(0, cardId.length() - 1));
        return cardId.charAt(cardId.length() - 1) == bit;
    }

    /**
     * 从不含校验位的银行卡卡号采用 Luhm 校验算法获得校验位
     */
    public static char getBankCardCheckCode(String nonCheckCodeCardId) {
        int cardLenth = nonCheckCodeCardId.trim().length();
        if (nonCheckCodeCardId == null || cardLenth == 0
                || !nonCheckCodeCardId.matches("\\d+")) {
            throw new IllegalArgumentException("不是银行卡的卡号!");
        }
        char[] chs = nonCheckCodeCardId.trim().toCharArray();
        int luhmSum = 0;
        for (int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
            int k = chs[i] - '0';

            if (j % 2 == 0) {
                k *= 2;
                k = k / 10 + k % 10;
            }
            luhmSum += k;
        }
        return (luhmSum % 10 == 0) ? '0' : (char) ((10 - luhmSum % 10) + '0');
    }

    // 计算时间之差精确到秒
    public static JSONObject getDistanceTime(String start, String nowTime) {
        JSONObject dataMap = new JSONObject();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d1;
        try {
            d1 = df.parse(nowTime);
            Date d2 = df.parse(start);
            long diff = d1.getTime() - d2.getTime();
            long seconds = diff / (1000); // 共计秒数
            long days = diff / (1000 * 60 * 60 * 24);
            long hours = (diff - days * (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
            long minutes = (diff - days * (1000 * 60 * 60 * 24) - hours * (1000 * 60 * 60)) / (1000 * 60);
            dataMap.put("days", days);
            dataMap.put("hours", hours);
            dataMap.put("minutes", minutes);
            dataMap.put("seconds", seconds);
            return dataMap;
        } catch (ParseException e) {
        } // 当前时间
        return dataMap;

    }

    // 判断当前时间是否在一个时间区间内
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime.getTime() == startTime.getTime()
                || nowTime.getTime() == endTime.getTime()) {
            return true;
        }

        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        return date.after(begin) && date.before(end);
    }

    // 字符串去重并且顺序不变
    public static String removeDuplicateLetters(String str) {
        if (StringUtils.isEmpty(str)) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            char everyword = str.charAt(i);
            int firstIndex = str.indexOf(everyword);
            int lastIndex = str.lastIndexOf(everyword);
            if (lastIndex == firstIndex || firstIndex == i) {
                sb.append(everyword);
            }
        }
        return sb.toString();
    }

    /**
     * 删除List中重复元素，并保持顺序
     *
     * @param list 待去重的list
     * @return 去重后的list
     */
    public static <T> List<T> removeDuplicateKeepOrder(List<T> list) {
        Set<T> set = new HashSet<T>();
        List<T> newList = new ArrayList<>();
        for (T element : list) {
            // set能添加进去就代表不是重复的元素
            if (set.add(element)) {
                newList.add(element);
            }
        }
        list.clear();
        list.addAll(newList);
        return list;
    }

    /*
     * 时间比大小
     * 如果参数字符串等于此字符串，则返回值 0；
     * 如果此字符串小于字符串参数，则返回一个小于 0 的值；
     * 如果此字符串大于字符串参数，则返回一个大于 0 的值。
     */
    public static int timeCompare(String t1, String t2) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        try {
            c1.setTime(formatter.parse(t1));
            c2.setTime(formatter.parse(t2));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        int result = c1.compareTo(c2);
        return result;
    }

    // 日期转string
    public static String dateToStrLong(Date dateDate) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(dateDate);
        return dateString;
    }

    // 生成随机用户名，数字和字母组成,
    public static String getRandomCharacters() {
        String val = "";
        Random random = new Random();
        // 参数length，表示生成几位随机数
        for (int i = 0; i < 10; i++) {
            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            // 输出字母还是数字
            if ("char".equalsIgnoreCase(charOrNum)) {
                // 输出是大写字母还是小写字母
                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
                val += (char) (random.nextInt(26) + temp);
            } else if ("num".equalsIgnoreCase(charOrNum)) {
                val += String.valueOf(random.nextInt(10));
            }
        }
        return val;
    }

    // object 转 map
    public static Map<String, Object> obj2Map(Object obj) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }

    //  开始时间为18:00，结束时间为09:00，有效区间为晚上18点到第二天早上9点
    public static boolean isTimeBetween(String startTimeStr, String endTimeStr) {
        // 当前时间
        LocalTime now = LocalTime.now();
        // 解析字符串时间
        LocalTime startTime = LocalTime.parse(startTimeStr);
        LocalTime endTime = LocalTime.parse(endTimeStr);

        // 如果当前时间在startTime和endTime之间，包括startTime和endTime
        return !now.isBefore(startTime) || !now.isAfter(endTime);

    }

    // 判断今天是否处于指定日期区间范围内，日期是字符串类型且是点号日期  2025.01.01-2025.0.1.01
    public static boolean isWithinDateRange(String startDate, String endDate) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");
        LocalDate now = LocalDate.now();
        return (now.isAfter(LocalDate.parse(startDate, formatter)) && now.isBefore(LocalDate.parse(endDate, formatter))) ||
                now.isEqual(LocalDate.parse(startDate, formatter)) ||
                now.isEqual(LocalDate.parse(endDate, formatter));
    }
}
